package com.brillilab.message.core;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.shade.com.alibaba.fastjson.JSON;
import com.brillilab.common.constant.KeyProfixConstant;
import com.brillilab.common.constant.ResultEnum;
import com.brillilab.common.entity.ResponseVo;
import com.brillilab.common.redis.RedisCache;
import com.brillilab.domain.po.lab.LabDevice;
import com.brillilab.domain.po.message.Message;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.message.core.enums.SocketEndPointEnum;
import com.brillilab.message.vo.SocketMessageVo;
import com.brillilab.service.core.message.IMessageService;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
@Component
@ServerEndpoint(value="/socket/{endPoint}/{token}")
public class SocketMessageSender implements MessageSender<SocketMessageVo> {

    public static IMessageService messageService;
    public static RedisCache redisCache;

    private Session session;
    private Integer endPoint;
    private Long userId;
    private String deviceNo;

    private static volatile ConcurrentHashMap<Long, List<Session>> userSessionPool=new ConcurrentHashMap<>();
    private static volatile ConcurrentHashMap<String, Session> aioSessionPool=new ConcurrentHashMap<>();

    /**
     * 用户连接时触发
     *
     * @param session
     * @param endPoint
     * @param token
     */
    @OnOpen
    public void open(Session session,@PathParam(value="endPoint") String endPoint,@PathParam(value="token") String token) {

        this.endPoint=SocketEndPointEnum.getValue(endPoint);
        this.session=session;
        if(this.endPoint.equals(SocketEndPointEnum.AIO.getValue())){
            //一体机session
            LabDevice labDeviceCache=this.getLabDeviceCache(token);
            if(labDeviceCache!=null){
                this.deviceNo=labDeviceCache.getDeviceNo();
                aioSessionPool.put(this.deviceNo,session);
            }else {
                closeSession(session);
            }
        } else {
            //非一体机session
            UserInfoVo userInfo = this.getUserCache(token);
            if(userInfo!=null){
                this.userId=userInfo.getId();
                addSessionToUserSessionMapper(session,userInfo);
            }else {
                closeSession(session);
            }
        }

    }

    private void closeSession(Session session) {
        try {
            String rs=JSONObject.toJSONString(ResponseVo.failure(ResultEnum.USER_NOT_LOGIN));
            session.getBasicRemote().sendText(rs);
            session.close();
            log.error("连接信息错误！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private synchronized void addSessionToUserSessionMapper(Session session,UserInfoVo userInfo) {
        List<Session> sessions=userSessionPool.get(this.userId);
        if(sessions == null){
            sessions=new CopyOnWriteArrayList<>();
        }
        sessions.add(session);

        userSessionPool.put(userInfo.getId(),sessions);
    }

    private LabDevice getLabDeviceCache(String token) {
        Object obj=redisCache.getObj(KeyProfixConstant.TOKEN+token);
        if(obj instanceof LabDevice){
            return (LabDevice) obj;
        }
        return null;
    }

    private UserInfoVo getUserCache(String token) {
        Object obj=redisCache.getObj(KeyProfixConstant.TOKEN+token);
        if(obj instanceof UserInfoVo){
            return (UserInfoVo) obj;
        }
        return null;
    }

    /**
     * 连接关闭触发
     */
    @OnClose
    public void onClose() {
        if(this.endPoint.equals(SocketEndPointEnum.AIO.getValue())){
            removeAioSession();
        } else{
            removeUserSession();
        }
    }

    private void removeAioSession() {
        if(StringUtils.isNotBlank(this.deviceNo)){
            aioSessionPool.remove(deviceNo);
        }
    }

    private synchronized void removeUserSession() {
        if(userId!=null){
            if(userSessionPool.get(userId) != null){
                List<Session> sessions=userSessionPool.get(userId);
                if(sessions.size() == 0){
                    userSessionPool.remove(userId);
                }
                sessions.remove(session);
            }
        }
    }

    @Override
    public boolean sendMessage(SocketMessageVo messageVo) {

        try {
            if(messageVo.isAio()){
                List<String> deviceNos=messageVo.getDeviceNos();
                for (String deviceNo : deviceNos) {
                    Session session=aioSessionPool.get(deviceNo);
                    session.getBasicRemote().sendText(messageVo.getBody());
                }
            }else {
                Long receiverId=messageVo.getReceiverId();
                List<Session> sessions=userSessionPool.get(receiverId);
                if(sessions!=null){
                    for (Session session:sessions){
                        session.getBasicRemote().sendText(messageVo.getBody());
                    }
                }
            }
        } catch (IOException e) {
            log.error("信息发送异常：",e);
            return false;
        }

        return true;
    }

    @Override
    public SocketMessageVo buildMessageVo(String messageData) {
        Message message = new Message();
        String pushContent="";
        Map<String, Object> resultMap=new LinkedHashMap<>();
        try {
            message = JSONObject.parseObject(messageData,Message.class);//messageService.selectById(messageId);
            if(message!=null){
                if(StringUtils.isNotBlank(message.getData())){
                    resultMap.put("exDate",message.getData());
                }
                resultMap.put("msgId",message.getId());
                resultMap.put("pushType", message.getType());
                resultMap.put("content",message.getContent());
                resultMap.put("title",message.getTitle());
                resultMap.put("referId",message.getReferId());
                resultMap.put("labId",message.getLabId());
                resultMap.put("receiverId",message.getReceiverId());
                resultMap.put("labMemberId",message.getLabMemberId());

                pushContent= JSON.toJSONString(ResponseVo.success(resultMap));
                //log.info("pushContent"+pushContent);
            }
        }catch (Exception e){
            log.error("异常：",e);
        }

        return new SocketMessageVo(message.getTitle(),pushContent,message.getReceiverId());

    }

    public SocketMessageVo buildMessageVo(String title,String body,List<String> deviceNos) {

        return new SocketMessageVo(title,body,deviceNos);

    }
}
